/////////////////////////////////////////////////////////////////////////////
// Name:        types.cpp
// Author:      Nicolay Giraldo
// Created:     14/04/06
// Copyright:   Nicolay Giraldo
/////////////////////////////////////////////////////////////////////////////

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#  include <wx/wx.h>
#endif

//#include <wx/log.h>
#include <wx/regex.h>
#include <wx/datetime.h>

#include <tommath.h>

#include <wx/dynarray.h>

#include "types.h"
#include "standardfunctions.h"

//#include "interpreter.h"


const wxChar *mp_sw_rmap = _T("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/");


void MessBox(const wxChar *pszFormat,...)
{
    va_list argptr;
    va_start(argptr, pszFormat);
	
    wxString mess;
	mess.Printf(pszFormat, va_pass(argptr));
	wxMessageBox(mess);
	
    va_end(argptr);
}



singlefloat::singlefloat(const number& n) : num(0) 
{
	switch (n.getType())
	{
	case t_singlefloat : num = ((singlefloat*)&n)->num; break;
//	case t_doublefloat : num = ((doublefloat)n).num; break;
//	case t_fixnum      : num = ((fixnum     )n).num; break;
	default            : break;
	}
	//TODO: conversion from other types of numbers... et al
}

number& 
singlefloat::operator + (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
	case t_singlefloat : return *(new singlefloat(num + ((singlefloat*)&n)->num));
	default            : return ((number*)&n)->operator+((number&)*this);
	}
}


number& 
singlefloat::operator ++ ()
{ 
	// TODO: overflow check ?
	num ++;
	return *this;
}


number& 
singlefloat::operator - ()
{ 
	return *(new singlefloat(-num));
}


number& 
singlefloat::operator - (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
	case t_singlefloat : return *(new singlefloat(num - ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num - ((doublefloat*)&n)->num));
	case t_fixnum      : return *(new singlefloat(num - ((fixnum     *)&n)->num));
//	case t_bignum      : TODO
	case t_ratio       : return - (((ratio*)&n)->operator-(*this));
	default            : return *this;
	}
}


number& 
singlefloat::operator * (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
	case t_singlefloat : return *(new singlefloat(num * ((singlefloat*)&n)->num));
//	case t_doublefloat : return singlefloat(num + ((doublefloat)n).num); break;
//	case t_fixnum      : return singlefloat(num + ((fixnum    )n).num); break;
	default            : return ((number*)&n)->operator*((number&)*this);
	}
}


number& 
singlefloat::operator /  (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
	case t_singlefloat : return *(new singlefloat(num / ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num / ((doublefloat*)&n)->num));
	case t_fixnum      : return *(new singlefloat(num / ((fixnum     *)&n)->num));
//	case t_fixnum      : return singlefloat(num + ((fixnum    )n).num); break;
	default            : return *this;
	}
}



value*
singlefloat::operator < (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
	case t_singlefloat : return num < ((singlefloat*)&n)->num ? trueval() : NULL;
	case t_doublefloat : return num < ((doublefloat*)&n)->num ? trueval() : NULL;
	case t_fixnum      : return num < ((fixnum     *)&n)->num ? trueval() : NULL;
	default            : return NULL;
	}
}


value*
singlefloat::operator <= (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
	case t_singlefloat : return num <= ((singlefloat*)&n)->num ? trueval() : NULL;
	case t_doublefloat : return num <= ((doublefloat*)&n)->num ? trueval() : NULL;
	case t_fixnum      : return num <= ((fixnum     *)&n)->num ? trueval() : NULL;
	default            : return NULL;
	}
}


number& 
singlefloat::operator -- ()
{ 
	// TODO: underflow check ?
	num --;
	return *this;
}


doublefloat::doublefloat(const number& n) : num(0) 
{
	switch (n.getType())
	{
	case t_singlefloat : num = ((singlefloat*)&n)->num; break;
	case t_doublefloat : num = ((doublefloat*)&n)->num; break;
	case t_fixnum      : num = ((fixnum     *)&n)->num; break;
	default            : break;
	}
	//TODO: conversion from other types of numbers... et al
}


number& 
doublefloat::operator + (const number& n)
{ 
	switch (n.getType())
	{
	case t_singlefloat : return *(new doublefloat(num + ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num + ((doublefloat*)&n)->num));
	case t_fixnum      : return *(new doublefloat(num + ((fixnum     *)&n)->num));
	default            : return ((number*)&n)->operator+((number&)*this);
	}
}


number& 
doublefloat::operator ++ ()
{ 
	num ++;
	return *this;
}


number& 
doublefloat::operator - ()
{ 
	return *(new doublefloat(-num));
}


number& 
doublefloat::operator - (const number& n)
{ 
	switch (n.getType())
	{
	case t_singlefloat : return *(new doublefloat(num - ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num - ((doublefloat*)&n)->num));
	case t_fixnum      : return *(new doublefloat(num - ((fixnum     *)&n)->num));
//	case t_bignum      : TODO
	case t_ratio       : return - (((ratio*)&n)->operator-(*this));
	default            : return *this;
	}
}


number& 
doublefloat::operator * (const number& n)
{ 
	switch (n.getType())
	{
	case t_singlefloat : return *(new doublefloat(num * ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num * ((doublefloat*)&n)->num));
	case t_fixnum      : return *(new doublefloat(num * ((fixnum     *)&n)->num));
	default            : return ((number*)&n)->operator*((number&)*this);
	}
}


number& 
doublefloat::operator /  (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
	case t_singlefloat : return *(new doublefloat(num / ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num / ((doublefloat*)&n)->num));
	case t_fixnum      : return *(new doublefloat(num / ((fixnum     *)&n)->num));
	default            : return *this;
	}
}


value*
doublefloat::operator < (const number& n)
{ 
	switch (n.getType())
	{
	case t_singlefloat : return num < ((singlefloat*)&n)->num ? trueval() : NULL;
	case t_doublefloat : return num < ((doublefloat*)&n)->num ? trueval() : NULL;
	case t_fixnum      : return num < ((fixnum     *)&n)->num ? trueval() : NULL;
	default            : return NULL;
	}
}


value*
doublefloat::operator <= (const number& n)
{ 
	switch (n.getType())
	{
	case t_singlefloat : return num <= ((singlefloat*)&n)->num ? trueval() : NULL;
	case t_doublefloat : return num <= ((doublefloat*)&n)->num ? trueval() : NULL;
	case t_fixnum      : return num <= ((fixnum     *)&n)->num ? trueval() : NULL;
	default            : return NULL;
	}
}


number& 
doublefloat::operator -- ()
{ 
	num --;
	return *this;
}


fixnum::fixnum(const number& n) : num(0)
{
	switch (n.getType())
	{
	case t_singlefloat : num = (wxInt32)((singlefloat*)&n)->num; break;
	case t_doublefloat : num = (wxInt32)((doublefloat*)&n)->num; break;
	case t_fixnum      : num = ((fixnum*)&n)->num; break;
	default            : break;
	}
	//TODO: conversion from other types of numbers... et al
}


wxInt32 fixnum::most_positive_fixnum = 2147483647;
wxInt32 fixnum::most_negative_fixnum = (-fixnum::most_positive_fixnum-1);


number& 
fixnum::operator + (const number& n)
{ 
	switch (n.getType())
	{
	case t_singlefloat : return *(new singlefloat(num + ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num + ((doublefloat*)&n)->num));
	case t_fixnum      : 
		{
			wxInt32 other =((fixnum*)&n)->num;
			wxInt32 result = num + other;
			int overflow = (num & other & ~result) | (~num & ~other & result);
			if (overflow < 0)
			{
//				wxLogError(_T("Overflow in a sum: %d + %d = %d"), num, other, result);
				return (*(new bignum (num))) + (*(new bignum (other)));
			}
			return *(new fixnum (result));
		}
	default            : return ((number*)&n)->operator+((number&)*this);
	}
}


number& 
fixnum::operator - ()
{ 
	if (num == fixnum::most_negative_fixnum)
	{
		return *(new bignum(bignum::least_positive_bignum));
	}
	return *(new fixnum(-num));
}


number& 
fixnum::operator - (const number& n)
{ 
	switch (n.getType())
	{
	case t_singlefloat : return *(new singlefloat(num - ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num - ((doublefloat*)&n)->num));
	case t_fixnum      : 
		{
			wxInt32 other =((fixnum*)&n)->num;
			wxInt32 result = num - other;
			int underflow = (num & ~other & ~result) | (~num & other & result);
			if (underflow < 0)
			{
//				wxLogError(_T("Underflow in a dif: %d + %d = %d"), num, other, result);
				return (*(new bignum (num))) - (*(new bignum (other)));
			}
			return *(new fixnum (result));
		}
	case t_bignum      : 
	case t_ratio       : return - (((ratio*)&n)->operator-(*this));
	default            : return *this;
	}
}



number& 
fixnum::operator -- ()
{ 
	if (num == most_negative_fixnum)
	{
		return *((new bignum(most_negative_fixnum)) - 1);
	}
	num --;
	return *this;
}


number& 
fixnum::operator * (const number& n)
{ 
	switch (n.getType())
	{
	case t_singlefloat : return *(new singlefloat(num * ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num * ((doublefloat*)&n)->num));
	case t_fixnum      : 
		{
			wxInt32 other =((fixnum*)&n)->num;
			wxInt32 result = num * other;
			// how do we test overflow?  using wxInt64 or using a division?
			// the answer is, in my hardware and testing with benchmarks, 
			// 64 bits multiplication is more expensive than 32 bits division
			// (84 vs 63 segs) so for now we will use division.
			// in other hardware the opposite will be true, so this should be configurable
			if (result)
			{
				int overflow = false;
				if (result/other != num)
				{
					overflow = true;
				}
				if (overflow)
				{
	//				wxLogError(_T("Overflow in a multiplication: %d * %d = %d"), num, other, result);
					return (*(new bignum (num))) * (*(new bignum (other)));
				}
			}
			return *(new fixnum (result));
		}
	case t_bignum     : return ((number*)&n)->operator*((number&)*this);
	default           : return ((number*)&n)->operator*((number&)*this);
	}
}


number& 
fixnum::operator / (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
	case t_singlefloat : return *(new singlefloat(num / ((singlefloat*)&n)->num));
	case t_doublefloat : return *(new doublefloat(num / ((doublefloat*)&n)->num));
	case t_fixnum      : 
		if (((fixnum*)&n)->num != 0)
		{
			if (num % ((fixnum*)&n)->num == 0)
			{
				return *(new fixnum(num / ((fixnum*)&n)->num));
			}
			else
			{
//				wxLogError(_T("Division not exact: %d / %d = %d"), num, ((fixnum*)&n)->num, num / ((fixnum*)&n)->num);
				return *(new ratio((*(integer*)this), *((integer*)&n)));
			}
		}
		else
		{
			wxLogError(_T("Division by zero: %d / 0"), num);
			return *this;
		}
	case t_bignum      : 
		if (((bignum*)&n)->num.used != 0)
		{
//			wxLogError(_T("Division not exact: %d / %d = %d"), num, ((fixnum*)&n)->num, num / ((fixnum*)&n)->num);
			return *(new ratio((*(integer*)this), *((integer*)&n)));
		}
		else
		{
			wxLogError(_T("Division by zero: %d / 0"), num);
			return *this;
		}
	case t_ratio       : return (((ratio*)&n)->reciprocal())->operator*(*this);
	default            : return *this;
	}
}


value* 
fixnum::operator < (const number& n)
{ 
	switch (n.getType())
	{
//	case t_singlefloat : return *(new singlefloat(num - ((singlefloat*)&n)->num));
//	case t_doublefloat : return *(new doublefloat(num - ((doublefloat*)&n)->num));
	case t_fixnum      : return num < ((fixnum*)&n)->num ? trueval() : NULL;
	case t_bignum      : return (((bignum*)&n)->num.sign == MP_ZPOS) ? trueval() : NULL;
	default            : return NULL;
	}
}


value* 
fixnum::operator <= (const number& n)
{ 
	switch (n.getType())
	{
//	case t_singlefloat : return *(new singlefloat(num - ((singlefloat*)&n)->num));
//	case t_doublefloat : return *(new doublefloat(num - ((doublefloat*)&n)->num));
	case t_fixnum      : return num <= ((fixnum*)&n)->num ? trueval() : NULL;
	case t_bignum      : return (((bignum*)&n)->num.sign == MP_ZPOS) ? trueval() : NULL;
	default            : return NULL;
	}
}


fixnum* 
fixnum::gcd (const fixnum* n)
{
	wxInt32 a = abs(num);
	wxInt32 b = abs((*n).num);
	if (a == 0 && b == 0)
	{
		return new fixnum();
	}
	if (a == 0)
	{
		return new fixnum(b);
	}
	if (b == 0)
	{
		return new fixnum(a);
	}
	while (b > 0)
	{
		if (a > b)
		{
			wxInt32 temp = a;
			a = b;
			b = temp;
		}
		b = b - a;
	}
	return new fixnum(a);
}


bignum::bignum(const wxInt32 n)
{
	mp_init(&num);
	unsigned long nn = n;
	bool negated = false;
	if (n < 0)
	{
		negated = true;
		nn =  -n;
	}
	status =  mp_set_int(&num, nn);
	if (negated)
	{
		status =  mp_neg(&num, &num);
	}
}


bignum* 
bignum::gcd (const bignum* n)
{
	bignum* result = new bignum();
	mp_gcd (&num, &(((bignum*)n)->num), &(result->num));
	return result;
}


bignum* 
bignum::gcd (const fixnum* n)
{
	return gcd(new bignum(n->num));
}


bignum bignum::most_positive_fixnum = (bignum(fixnum::most_positive_fixnum));
bignum bignum::most_negative_fixnum = (bignum(fixnum::most_negative_fixnum));
bignum bignum::least_positive_bignum = *((bignum*)&(bignum::most_positive_fixnum + fixnum(1)));
bignum bignum::least_negative_bignum = *((bignum*)&(bignum::most_negative_fixnum - fixnum(1)));;


unsigned int 
getmag(mp_int* num)
{
	mp_int t;
	mp_digit d;
	unsigned int result = 0;
	unsigned int power = 1;
	unsigned int radix = 128;
	if ((mp_init_copy (&t, num)) != MP_OKAY) {
		return 0;
	}
	
	while (mp_iszero (&t) == 0) {
		if ((mp_div_d (&t, (mp_digit)radix, &t, &d)) != MP_OKAY) {
			mp_clear (&t);
			return 0;
		}
		result += (d * power);
		power *= radix;
	}
	mp_clear (&t);
	return result;
}


integer& 
bignum::chkmag()
{
	wxInt32 result;
	if (num.sign == MP_ZPOS)
	{
		if (mp_cmp(&num, &(most_positive_fixnum.num)) == MP_LT)
		{
			result = getmag(&num);
			return *(new fixnum(result));
		}
	}
	if (num.sign == MP_NEG)
	{
		if (mp_cmp(&num, &(most_negative_fixnum.num)) == MP_GT)
		{
			result = getmag(&num);
			result *= -1;
			return *(new fixnum(result));
		}
	}
	return *this;
}


number& 
bignum::operator + (const number& n)
{ 
	switch (n.getType())
	{
	// TODO: sum with single and double floats
//	case t_singlefloat : return *(new singlefloat(num + ((singlefloat)n).num));
//	case t_longfloat   : return *(new longfloat (num + ((longfloat )n).num));
	case t_fixnum      : 
		{
			bignum* result = new bignum();
			mp_add_d (&num, (mp_digit) ((fixnum*)&n)->num, &(result->num));
			number& nresult = result->chkmag();
			return nresult;
		}
	case t_bignum      : 
		{
			bignum* result = new bignum();
			bignum* addendum = (bignum*)(&n);
			mp_add (&num, &(addendum->num), &(result->num));
			number& nresult = result->chkmag();
			return nresult;
		}
	default            : return ((number*)&n)->operator+((number&)*this);
	}
}


number& 
bignum::operator - ()
{
	if (mp_cmp(&num, &(least_positive_bignum.num)) == MP_EQ)
	{
		return *(new fixnum(fixnum::most_negative_fixnum));
	}
	bignum* result = new bignum();
	mp_neg(&num, &(result->num));
	return *(result);
}


number& 
bignum::operator - (const number& n)
{ 
	switch (n.getType())
	{
	// TODO: dif with single and double floats
//	case t_singlefloat : return *(new singlefloat(num + ((singlefloat)n).num));
//	case t_longfloat  : return *(new longfloat (num + ((longfloat )n).num));
	case t_fixnum     :
		{
			bignum* result = new bignum();
			bignum* sustraendum = new bignum((wxInt32)(((fixnum*)&n)->num));
			mp_sub (&num, &(sustraendum->num), &(result->num));
			number& nresult = result->chkmag();
			return nresult;
		}
	case t_bignum     :
		{
			bignum* result = new bignum();
			bignum* sustraendum = (bignum*)(&n);
			mp_sub (&num, &(sustraendum->num), &(result->num));
			number& nresult = result->chkmag();
			return nresult;
		}
	case t_ratio       : return - (((ratio*)&n)->operator-(*this));
	default            : return *this;
	}
}


number& 
bignum::operator -- ()
{
	status = mp_sub_d(&num, (mp_digit)1, &num);
	// TODO: test for most positive fixnum
//	if (num)
//	{
//	}
	return *this;
}


number& 
bignum::operator * (const number& n)
{ 
	switch (n.getType())
	{
//	case t_singlefloat : return *(new singlefloat(num + ((singlefloat)n).num));
//	case t_longfloat   : return *(new longfloat (num + ((longfloat )n).num));
	case t_fixnum      : 
		{
			bignum* result = new bignum();
			bignum* factor = new bignum(((fixnum*)&n)->num);
			mp_mul (&num, &(factor->num), &(result->num));
			return *result;
		}
	case t_bignum      : 
		{
			bignum* result = new bignum();
			bignum* factor = (bignum*)(&n);
			mp_mul (&num, &(factor->num), &(result->num));
			return *result;
		}
	default            : return ((number*)&n)->operator*((number&)*this);
	}
}


number& 
bignum::operator /  (const number& n)
{ 
	// TODO: overflow check ?
	switch (n.getType())
	{
//	case t_singlefloat : return *(new singlefloat(num / ((singlefloat*)&n)->num));
//	case t_doublefloat : return *(new doublefloat(num / ((doublefloat*)&n)->num));
	case t_fixnum      : 
		{
			bignum* divisor = new bignum(((fixnum*)&n)->num);
			bignum* result = new bignum();
			bignum* remainder = new bignum();
			status = mp_div(&num, &(divisor->num), &(result->num), &(remainder->num));
			if (status == MP_VAL)
			{
				wxLogError(_T("Division by zero: %d / %d"), num, ((fixnum*)&n)->num);
				return *this;
			}
			if (remainder->num.used == 0)
			{
				number& nresult = result->chkmag();
				return nresult;
			}
			else
			{
//				wxLogError(_T("Division not exact 1"));
				return *(new ratio((*(integer*)this), *((integer*)&n)));
//				return *this;
			}
		}
	case t_bignum      : 
		{
			bignum* result = new bignum();
			bignum* remainder = new bignum();
			status = mp_div(&num, &((bignum*)&n)->num, &(result->num), &(remainder->num));
			if (status == MP_VAL)
			{
				wxLogError(_T("Division by zero: %d / %d"), num, ((fixnum*)&n)->num);
				return *this;
			}
			if (remainder->num.used == 0)
			{
				number& nresult = result->chkmag();
				return nresult;
			}
			else
			{
//				wxLogError(_T("Division not exact 2"));
				return *(new ratio((*(integer*)this), *((integer*)&n)));
			}
		}
	case t_ratio       : return (((ratio*)&n)->reciprocal())->operator*(*this);
	default            : return *this;
	}
}


value* 
bignum::operator < (const number& n)
{ 
	switch (n.getType())
	{
//	case t_singlefloat : return *(new singlefloat(num - ((singlefloat*)&n)->num));
//	case t_doublefloat : return *(new doublefloat(num - ((doublefloat*)&n)->num));
	case t_fixnum      : return num.sign == MP_NEG ? trueval() : NULL;
	case t_bignum      : return mp_cmp(&num, &(((bignum*)(&n))->num)) == MP_LT ? trueval() : NULL;
	default            : return NULL;
	}
}


value* 
bignum::operator <= (const number& n)
{ 
	switch (n.getType())
	{
//	case t_singlefloat : return *(new singlefloat(num - ((singlefloat*)&n)->num));
//	case t_doublefloat : return *(new doublefloat(num - ((doublefloat*)&n)->num));
	case t_fixnum      : return num.sign == MP_NEG ? trueval() : NULL;
	case t_bignum      : 
		{
		int res = mp_cmp(&num, &(((bignum*)(&n))->num));
		return (res == MP_LT || res == MP_EQ) ? trueval() : NULL;
		}
	default            : return NULL;
	}
}


ratio::ratio(integer& numer, integer& denom)
	: numerator(&numer), denominator(&denom)
{
	adjustgcd();
}


ratio::ratio(ratio& cc)
{
	switch (cc.numerator->getType())
	{
	case t_bignum: numerator = (new bignum(*((bignum*)cc.numerator))); break;
	case t_fixnum: numerator = (new fixnum(*((fixnum*)cc.numerator))); break;
	default      : break;
	}
	switch (cc.denominator->getType())
	{
	case t_bignum: denominator = (new bignum(*((bignum*)cc.denominator))); break;
	case t_fixnum: denominator = (new fixnum(*((fixnum*)cc.denominator))); break;
	default      : break;
	}
}


void 
ratio::adjustgcd()
{
	integer* gcdres;
	if (numerator->getType() == t_bignum && denominator->getType() == t_bignum)
	{
		gcdres = (integer*)&(((bignum*)numerator)->gcd((bignum*)denominator)->chkmag());
	}
	else if (numerator->getType() == t_bignum)
	{
		gcdres = (integer*)&(((bignum*)numerator)->gcd((fixnum*)denominator)->chkmag());
	}
	else if (denominator->getType() == t_bignum)
	{
		gcdres = (integer*)&(((bignum*)denominator)->gcd((fixnum*)numerator)->chkmag());
	}
	else
	{
		gcdres = ((fixnum*)numerator)->gcd((fixnum*)denominator);
	}
	numerator = ((integer*)&(numerator->operator/(*gcdres)));
	denominator = ((integer*)&(denominator->operator/(*gcdres)));
}


rational& 
ratio::chkdenom()
{
	if (denominator->getType() == t_fixnum && ((fixnum*)denominator)->num == 1)
	{
		return *numerator;
	}
	return *this;
}


ratio* 
ratio::reciprocal()
{
	// copy constructor (or something like that)
	integer* numer = ((denominator->getType() == t_fixnum) ? (integer*)new fixnum((fixnum&)*denominator) : (integer*)new bignum((bignum&)*denominator));
	integer* denom = ((numerator->getType() == t_fixnum) ? (integer*)new fixnum((fixnum&)*numerator) : (integer*)new bignum((bignum&)*numerator));
	return new ratio(*numer, *denom);
}


number& 
ratio::operator +  (const number& n)
{
	switch (n.getType())
	{
	case t_singlefloat : return ((numerator->operator*(*(new singlefloat(1.0)))) + 
		(denominator->operator*(n))) / 
		(denominator->operator*(*(new singlefloat(1.0))));
	case t_doublefloat : return ((numerator->operator*(*(new doublefloat(1.0)))) + 
		(denominator->operator*(n))) / 
		(denominator->operator*(*(new doublefloat(1.0))));
	case t_fixnum      : 
	case t_bignum      : return ((new ratio((integer&)((numerator->operator*(*(new fixnum(1)))) + 
		(denominator->operator*(n))), (integer&)(denominator->operator*(*(new fixnum(1))))))->chkdenom());
	case t_ratio       : 
		{
			number& numer = *(((ratio*)&n)->numerator);
			number& denom = *(((ratio*)&n)->denominator);
			return ((new ratio((integer&)((numerator->operator*(denom)) + (denominator->operator*( numer ))), 
				(integer&)(denominator->operator*(denom))))->chkdenom());
		}
	default           : return ((number*)&n)->operator+((number&)*this);
	}
}


number& 
ratio::operator ++ ()
{
	numerator = (integer*)(&(numerator->operator+(*denominator)));
	return *this;
}


number& 
ratio::operator -  ()
{
	ratio* result = new ratio(*this);
	result->numerator = (integer*)(&(- *(numerator)));
	return *result;
}


number& 
ratio::operator -  (const number& n)
{
	switch (n.getType())
	{
	case t_singlefloat : return ((numerator->operator*(*(new singlefloat(1.0)))) -
		(denominator->operator*(n))) / 
		(denominator->operator*(*(new singlefloat(1.0))));
	case t_doublefloat : return ((numerator->operator*(*(new doublefloat(1.0)))) -
		(denominator->operator*(n))) / 
		(denominator->operator*(*(new doublefloat(1.0))));
	case t_fixnum      : 
	case t_bignum      : return ((new ratio((integer&)((numerator->operator*(*(new fixnum(1)))) -
		(denominator->operator*(n))), (integer&)(denominator->operator*(*(new fixnum(1))))))->chkdenom());
	case t_ratio       : 
		{
			number& numer = *(((ratio*)&n)->numerator);
			number& denom = *(((ratio*)&n)->denominator);
			return ((new ratio((integer&)((numerator->operator*(denom)) - (denominator->operator*( numer ))), 
				(integer&)(denominator->operator*(denom))))->chkdenom());
		}
	default           : return *this;
	}
}


number& 
ratio::operator -- ()
{
	numerator = (integer*)(&(numerator->operator-(*denominator)));
	return *this;
}


number& 
ratio::operator *  (const number& n)
{
	switch (n.getType())
	{
	case t_singlefloat : return ((numerator->operator*(n)) / (denominator->operator*(*(new singlefloat(1.0)))));
	case t_doublefloat : return ((numerator->operator*(n)) / (denominator->operator*(*(new doublefloat(1.0)))));
	case t_fixnum      : 
	case t_bignum      : return ((new ratio((integer&)((numerator->operator*(n))), (integer&)(denominator->operator*(*(new fixnum(1))))))->chkdenom());
	case t_ratio       : 
		{
			number& numer = *(((ratio*)&n)->numerator);
			number& denom = *(((ratio*)&n)->denominator);
			return ((new ratio((integer&)((numerator->operator*(numer))), 
				(integer&)(denominator->operator*(denom))))->chkdenom());
		}
	default           : return ((number*)&n)->operator*((number&)*this);
	}
}


number& 
ratio::operator /  (const number& n)
{
	switch (n.getType())
	{
	case t_singlefloat : return ((numerator->operator*(*(new singlefloat(1.0)))) / (denominator->operator*(n)));
	case t_doublefloat : return ((numerator->operator*(*(new doublefloat(1.0)))) / (denominator->operator*(n)));
	case t_fixnum      : 
	case t_bignum      : return ((new ratio((integer&)((numerator->operator*(*(new fixnum(1))))), (integer&)(denominator->operator*(n))))->chkdenom());
	case t_ratio       : 
		{
			number& numer = *(((ratio*)&n)->numerator);
			number& denom = *(((ratio*)&n)->denominator);
			return ((new ratio((integer&)((numerator->operator*(denom))), 
				(integer&)(denominator->operator*(numer))))->chkdenom());
		}
	default           : return *this;
	}
}


value*  
ratio::operator <  (const number& WXUNUSED(n))
{
	return NULL;
}


value*  
ratio::operator <= (const number& WXUNUSED(n))
{
	return NULL;
}


int 
bignum::read(wxString& source, int radix)
{
	int y, res, neg;
	wxChar ch;

	/* zero the digit bignum */
	mp_zero(&num);
	
	/* make sure the radix is ok */
	if (radix < 2 || radix > 64) {
		return MP_VAL;
	}
	
	if (radix < 36) source.MakeUpper();
	const wxChar* str = source.c_str();
	
	if (*str == _T('+') || *str == _T('-')) {
		if (*str == _T('-')) {
			neg = MP_NEG;
		} else {
			neg = MP_ZPOS;
		}
		++str;
	} 
	else 
		neg = MP_ZPOS;
	
		/* process each digit of the string */
	while (*str) {
		/* if the radix < 36 the conversion is case insensitive
		* this allows numbers like 1AB and 1ab to represent the same  value
		* [e.g. in hex]
		*/
		ch = (wxChar) *str;
		for (y = 0; y < 64; y++) {
			if (ch == mp_sw_rmap[y]) {
				break;
			}
		}
		
		/* if the char was found in the map 
		* and is less than the given radix add it
		* to the number, otherwise exit the loop. 
		*/
		if (y < radix) {
			if ((res = mp_mul_d (&num, (mp_digit) radix, &num)) != MP_OKAY) {
				return res;
			}
			if ((res = mp_add_d (&num, (mp_digit) y, &num)) != MP_OKAY) {
				return res;
			}
		} else {
			break;
		}
		++str;
	}
	
	/* set the sign only if a != 0 */
	if (mp_iszero(&num) != 1) {
		num.sign = neg;
	}
	return MP_OKAY;
}


void
bn_wreverse (wxChar *s, int len)
{
	int     ix, iy;
	wxChar t;
	
	ix = 0;
	iy = len - 1;
	while (ix < iy) {
		t     = s[ix];
		s[ix] = s[iy];
		s[iy] = t;
		++ix;
		--iy;
	}
}


int 
bignum::write(wxString& target, int radix)
{
	int     res, digs;
	mp_int  t;
	mp_digit d;
	int size;
	mp_radix_size (&num, radix, &size);
	target.Alloc(size);
	wxChar* _s = target.GetWriteBuf(size);
	wxChar* str = _s;
	
	/* check range of the radix */
	if (radix < 2 || radix > 64) {
		return MP_VAL;
	}
	
	/* quick out if its zero */
	if (mp_iszero(&num) == 1) {
		*str++ = '0';
		*str = '\0';
		return MP_OKAY;
	}
	
	if ((res = mp_init_copy (&t, &num)) != MP_OKAY) {
		return res;
	}
	
	/* if it is negative output a - */
	if (t.sign == MP_NEG) {
		++_s;
		*str++ = '-';
		t.sign = MP_ZPOS;
	}
	
	digs = 0;
	while (mp_iszero (&t) == 0) {
		if ((res = mp_div_d (&t, (mp_digit) radix, &t, &d)) != MP_OKAY) {
			mp_clear (&t);
			return res;
		}
		*str++ = mp_s_rmap[d];
		++digs;
	}
	
	/* reverse the digits of the string.  In this case _s points
	* to the first digit [exluding the sign] of the number]
	*/
	bn_wreverse ((wxChar *)_s, digs);
	
	/* append a NULL so the string is properly terminated */
	*str = '\0';
	
	target.UngetWriteBuf(size);
	
	mp_clear (&t);
	return MP_OKAY;
}


value*
internalfunction::CallSystemFun()
{
	switch (numparams)
	{
	case  0: return (*(funptr.f00))();
	case  1: return (*(funptr.f01))(paramvalues[0]);
	case  2: return (*(funptr.f02))(paramvalues[0], paramvalues[1]);
	case  3: return (*(funptr.f03))(paramvalues[0], paramvalues[1], paramvalues[2]);
	case  4: return (*(funptr.f04))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3]);
	case  5: return (*(funptr.f05))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4]);
	case  6: return (*(funptr.f06))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5]);
	case  7: return (*(funptr.f07))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6]);
	case  8: return (*(funptr.f08))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7]);
	case  9: return (*(funptr.f09))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8]);
	case 10: return (*(funptr.f10))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9]);
	case 11: return (*(funptr.f11))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10]);
	case 12: return (*(funptr.f12))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11]);
	case 13: return (*(funptr.f13))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12]);
	case 14: return (*(funptr.f14))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13]);
	case 15: return (*(funptr.f15))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14]);
	case 16: return (*(funptr.f16))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15]);
	case 17: return (*(funptr.f17))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16]);
	case 18: return (*(funptr.f18))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17]);
	case 19: return (*(funptr.f19))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18]);
	case 20: return (*(funptr.f20))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19]);
	case 21: return (*(funptr.f21))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20]);
	case 22: return (*(funptr.f22))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21]);
	case 23: return (*(funptr.f23))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22]);
	case 24: return (*(funptr.f24))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23]);
	case 25: return (*(funptr.f25))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24]);
	case 26: return (*(funptr.f26))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25]);
	case 27: return (*(funptr.f27))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26]);
	case 28: return (*(funptr.f28))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27]);
	case 29: return (*(funptr.f29))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28]);
	case 30: return (*(funptr.f30))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29]);
	case 31: return (*(funptr.f31))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30]);
	case 32: return (*(funptr.f32))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31]);
	case 33: return (*(funptr.f33))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32]);
	case 34: return (*(funptr.f34))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33]);
	case 35: return (*(funptr.f35))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34]);
	case 36: return (*(funptr.f36))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35]);
	case 37: return (*(funptr.f37))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36]);
	case 38: return (*(funptr.f38))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37]);
	case 39: return (*(funptr.f39))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38]);
	case 40: return (*(funptr.f40))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39]);
	case 41: return (*(funptr.f41))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40]);
	case 42: return (*(funptr.f42))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41]);
	case 43: return (*(funptr.f43))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41], paramvalues[42]);
	case 44: return (*(funptr.f44))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41], paramvalues[42], paramvalues[43]);
	case 45: return (*(funptr.f45))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41], paramvalues[42], paramvalues[43], paramvalues[44]);
	case 46: return (*(funptr.f46))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41], paramvalues[42], paramvalues[43], paramvalues[44], paramvalues[45]);
	case 47: return (*(funptr.f47))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41], paramvalues[42], paramvalues[43], paramvalues[44], paramvalues[45], paramvalues[46]);
	case 48: return (*(funptr.f48))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41], paramvalues[42], paramvalues[43], paramvalues[44], paramvalues[45], paramvalues[46], paramvalues[47]);
	case 49: return (*(funptr.f49))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41], paramvalues[42], paramvalues[43], paramvalues[44], paramvalues[45], paramvalues[46], paramvalues[47], paramvalues[48]);
	case 50: return (*(funptr.f50))(paramvalues[0], paramvalues[1], paramvalues[2], paramvalues[3], paramvalues[4], paramvalues[5], paramvalues[6], paramvalues[7], paramvalues[8], paramvalues[9], paramvalues[10], paramvalues[11], paramvalues[12], paramvalues[13], paramvalues[14], paramvalues[15], paramvalues[16], paramvalues[17], paramvalues[18], paramvalues[19], paramvalues[20], paramvalues[21], paramvalues[22], paramvalues[23], paramvalues[24], paramvalues[25], paramvalues[26], paramvalues[27], paramvalues[28], paramvalues[29], paramvalues[30], paramvalues[31], paramvalues[32], paramvalues[33], paramvalues[34], paramvalues[35], paramvalues[36], paramvalues[37], paramvalues[38], paramvalues[39], paramvalues[40], paramvalues[41], paramvalues[42], paramvalues[43], paramvalues[44], paramvalues[45], paramvalues[46], paramvalues[47], paramvalues[48], paramvalues[49]);
	default: return NULL;
	}
}

value*
internalfunction::Call()
{
	switch (ftype)
	{
	case f_systemfunction  : return CallSystemFun();
	case f_function        : return NULL;
	case f_genericfunction : return NULL;
	case f_method          : return NULL;
	case f_closure         : return NULL;
	case f_macro           : return NULL;
	case f_specialop       : return NULL;
	default: return NULL;
	}
}
